/* eslint-disable no-unused-vars */
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
import { Piece, PieceProps } from '@/types/piece'

// 用户状态
export interface pieceState {
  storePieces: Piece[]
  isLoaded: boolean
  isLoading: boolean
  loadAllPieces: () => Promise<void>
  /**
   * 只加载一次所有碎片属性，已加载则不再请求
   */
  loadPieceProps: () => Promise<void>
  storePieceProps: Record<number, PieceProps>
  addpiece: (piece: Piece | null) => Piece | null
  addpieces: (pieces: Piece[]) => Piece[]
  addPieceProps: (props: PieceProps | null) => PieceProps | null
  addPiecePropsBatch: (propsArr: PieceProps[]) => PieceProps[]
  getPiecePropsById: (id: number) => PieceProps | undefined
  getPiecePropsBatch: (ids: number[]) => PieceProps[]
  contains: (piece: Piece) => boolean
  clear: () => void
  clearPieceProps: () => void
}

// 创建一个自定义的存储，带有过期逻辑
const createExpiringStorage = (storage: Storage, expireIn: number) => {
  return {
    getItem: (name: string) => {
      const item = storage.getItem(name)
      if (!item) return null

      const { value, expiry } = JSON.parse(item)
      if (Date.now() > expiry) {
        storage.removeItem(name)
        return null
      }
      return value
    },
    setItem: (name: string, value: unknown) => {
      const expiry = Date.now() + expireIn
      const item = JSON.stringify({ value, expiry })
      storage.setItem(name, item)
    },
    removeItem: (name: string) => {
      storage.removeItem(name)
    }
  }
}

// 检查 localStorage 是否可用
const isLocalStorageAvailable = () => {
  try {
    const testKey = '__test__'
    localStorage.setItem(testKey, testKey)
    localStorage.removeItem(testKey)
    return true
  } catch (e) {
    return false
  }
}

// 创建碎片
export const usePieceStore = create<pieceState>()(
  persist(
    (set, get: () => pieceState) => ({
      storePieces: [],
      isLoaded: false,
      isLoading: false,
      /**
       * 只加载一次所有碎片，已加载则不再请求
       */
      loadAllPieces: (() => {
        let loadingPromise: Promise<void> | null = null
        return async () => {
          if (get().isLoaded) return
          if (get().isLoading) {
            // 并发保护，等待已有的 promise
            if (loadingPromise) await loadingPromise
            return
          }
          set({ isLoading: true })
          loadingPromise = (async () => {
            try {
              const { loadPiece } = await import('@/apis/piece')
              const data = await loadPiece({ size: 999 })
              if (data && data.length > 0) {
                data.sort((b, a) => {
                  if (a.name !== b.name) {
                    return a.name.localeCompare(b.name)
                  }
                  if (a.props !== b.props) {
                    return a.props.localeCompare(b.props)
                  }
                  return a.score - b.score
                })
                set((state: pieceState) => ({
                  storePieces: [...state.storePieces, ...data],
                  isLoaded: true,
                  isLoading: false
                }))
              } else {
                set({ isLoaded: true, isLoading: false })
              }
            } catch (e) {
              set({ isLoading: false })
            } finally {
              loadingPromise = null
            }
          })()
          await loadingPromise
        }
      })(),
      /**
       * 只加载一次所有碎片属性，已加载则不再请求
       */
      loadPieceProps: (() => {
        let loadingPromise: Promise<void> | null = null
        let isLoaded = false
        let isLoading = false
        return async () => {
          if (isLoaded) return
          if (isLoading) {
            if (loadingPromise) await loadingPromise
            return
          }
          isLoading = true
          loadingPromise = (async () => {
            try {
              const { loadPieceProps } = await import('@/apis/piece')
              const data = await loadPieceProps()
              if (data && data.length > 0) {
                const newPropsMap = data.reduce(
                  (acc, cur) => {
                    acc[cur.id] = cur
                    return acc
                  },
                  {} as Record<number, PieceProps>
                )
                set((state: pieceState) => ({
                  storePieceProps: { ...state.storePieceProps, ...newPropsMap }
                }))
                isLoaded = true
              } else {
                isLoaded = true
              }
            } catch (e) {
              // ignore
            } finally {
              isLoading = false
              loadingPromise = null
            }
          })()
          await loadingPromise
        }
      })(),
      storePieceProps: {},
      addpiece: (piece: Piece | null) => {
        if (piece && !get().storePieces.some((s: Piece) => s.id === piece.id)) {
          set((state: pieceState) => ({
            storePieces: [...state.storePieces, piece]
          }))
          return piece
        }
        return null
      },
      addpieces: (pieces: Piece[]) => {
        const newpieces = pieces.filter(
          (piece) => !get().storePieces.some((s: Piece) => s.id === piece.id)
        )
        set((state: pieceState) => ({
          storePieces: [...state.storePieces, ...newpieces]
        }))
        return newpieces
      },
      addPieceProps: (props: PieceProps | null) => {
        if (props && !get().storePieceProps[props.id]) {
          set((state: pieceState) => ({
            storePieceProps: { ...state.storePieceProps, [props.id]: props }
          }))
          return props
        }
        return null
      },
      addPiecePropsBatch: (propsArr: PieceProps[]) => {
        const current = get().storePieceProps
        const newPropsArr = propsArr.filter((props) => !current[props.id])
        if (newPropsArr.length > 0) {
          const newPropsMap = newPropsArr.reduce(
            (acc, cur) => {
              acc[cur.id] = cur
              return acc
            },
            {} as Record<number, PieceProps>
          )
          set((state: pieceState) => ({
            storePieceProps: { ...state.storePieceProps, ...newPropsMap }
          }))
        }
        return newPropsArr
      },
      getPiecePropsById: (id: number) => {
        return get().storePieceProps[id]
      },
      getPiecePropsBatch: (ids: number[]) => {
        const propsMap = get().storePieceProps
        return ids.map((id) => propsMap[id]).filter(Boolean)
      },
      contains: (piece: Piece) => {
        return get().storePieces.some((s: Piece) => s.id === piece.id)
      },
      clear: () => {
        set({ storePieces: [] })
      },
      clearPieceProps: () => {
        set({ storePieceProps: {} })
      }
    }),
    {
      name: 'battle_piece_v1',
      storage: isLocalStorageAvailable()
        ? createExpiringStorage(localStorage, 1 * 60 * 60 * 1000)
        : undefined
      // storage: createJSONStorage(localStorage),
    }
  )
)
